﻿using System;

namespace configstore.CSM.Common
{
    using SanlieHash;
    using SanlieHash.Fast;
    using SanlieHash.GuoMi;
    using ExcelConfig;
    using wuo;
    using TouchSocket.Http;

    internal class ConfigStoreSession : IDisposable
    {
        internal IHttpSessionClient client { get; }
        internal HttpContextEventArgs e { get; }
        internal HttpRequest request { get; set; }
        internal HttpResponse response { get; set; }
        public ConfigStoreSession(IHttpSessionClient client, HttpContextEventArgs e)
        {
            this.client = client;
            this.e = e;
            this.request = e.Context.Request;
            this.response = e.Context.Response;
            IP = client.IP;
        }
        public string IP { get; protected set; }
        internal string Password = string.Empty;
        internal Guid DeviceID = Guid.Empty;
        internal static string decrypto_msg(string msg, out string password, out Guid deviceId)
        {
            deviceId = Guid.Empty;
            password = string.Empty;
            try
            {
                if (msg.IndexOf("#") == -1) return string.Empty;
                var passkey = msg.Substring(0, msg.IndexOf("#"));
                var pass = AppConfig.Text("验证密码");

                switch (passkey.Substring(0, passkey.IndexOf("_")))
                {
                    case "S1":
                        var guid = passkey.Substring(passkey.IndexOf("_")+1);
                        deviceId = new Guid(FastEncode.DecodeHex(guid));
                        var zuc = FastGuoMi.GetZUC(guid, pass);
                        zuc.Jump(pass.Length);
                        var _p1 = zuc.NextHex();
                        var _p2 = FastGuoMi.GetSM3($"S1_{_p1}-{pass}-{guid}");
                        password = pass = $"S1_{guid}-{_p1}-{_p2}";
                        msg = msg.Substring(msg.IndexOf("#") +1);
                        break;
                }
                
                if (msg.Length < 8) return string.Empty;
                var size = FastEncode.DecodeUInt(msg.Substring(0, 8));
                msg = msg.Substring(8);
                if (msg.Length < size) return string.Empty;
                var m1 = msg.Substring(0, (int)size);
                msg = msg.Substring((int)size);
                if (msg.Length < 8) return string.Empty;
                size = FastEncode.DecodeUInt(msg.Substring(0, 8));
                msg = msg.Substring(8);
                if (msg.Length < size) return string.Empty;
                var key = msg.Substring(0, (int)size);
                msg = msg.Substring((int)size);
                if (msg.Length < 8) return string.Empty;
                size = FastEncode.DecodeUInt(msg.Substring(0, 8));
                msg = msg.Substring(8);
                if (msg.Length < size) return string.Empty;
                msg = msg.Substring(0, (int)size);

                var buf = FastEncode.Base64Decode2Bytes(m1);
                var p1 = FastEncode.DecodeMorse(buf);
                var r = FastGuoMi.DecryptSM4(key, FastAES.Encrypt(pass, p1));
                buf = FastEncode.Base64Decode2Bytes(r);
                var p2 = FastEncode.DecodeMorse(buf);
                var msg_d = FastGuoMi.DecryptSM4(msg, p2);
                var p0 = FastGuoMi.EncryptSM4(pass, FastGuoMi.GetSM3(msg_d));
                if (p1 != FastGuoMi.GetSM3(p0)) return string.Empty;
                if (p2 != FastHash.GetMD6(p0 + pass)) return string.Empty;
                return msg_d;
            }
            catch { return string.Empty; }
        }
        public async Task<T?> GetData<T>() where T : class
        {
            var msg = await request.GetDataString();
            msg = decrypto_msg(msg, out Password, out DeviceID);
            if (string.IsNullOrEmpty(msg)) return null;
            return WuoConvert.DeserializeObject<T>(msg);
        }
        public IEnumerable<IFormFile> Files()
        {
            foreach (var file in request.GetMultifileCollection())
            {
                if (file == null) continue;
                if (file.ContentType == "text/plain") continue;
                yield return file;
            }
        }
        public bool IsPost(string uri)
        {
            return request.IsPost() && request.UrlEquals(uri);
        }
        public bool IsGet(string uri)
        {
            return request.IsGet() && request.UrlEquals(uri);
        }

        public Task InvokeNext()
        {
            return e.InvokeNext();
        }

        public async Task Send(int status, object obj, string message = "success")
        {
            response
                        .SetStatus(status, message)
                        .FromObj(obj);
            await response.AnswerAsync();
        }

        internal SM4 sm4 = new SM4();
        public async Task SendFile(int status, string filename, Stream stream, string message = "success")
        {
            sm4.New();
            sm4.SetKey(FastHash.GetMD5Bytes(Password));
            var buf = new byte[stream.Length];
            using (stream)
            {
                stream.Seek(0, SeekOrigin.Begin);
                var x = stream.Read(buf, 0, buf.Length);
            }
            using (var mem = new MemoryStream(sm4.Encrypt(buf)))
                await response.SetStatus(status, message)
                    .FromStreamAsync(filename,mem);
            //await response.AnswerAsync();
        }
        public void Dispose()
        {
        }
    }
}
